﻿#region license
# This file is part of Grawlix.
# 
# Grawlix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# 
# Grawlix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with Grawlix.  If not, see
# <http://www.gnu.org/licenses/>.
#endregion

"""
Testing for the expect macro.
Remarks: Since it relies on NUnit, I couldn't test failure without
	starting an inner instance of NUnit.
"""

namespace Grawlix.Meta.Tests
import Grawlix.Meta
import NUnit.Framework
import System

[TestFixture]
class ExpectSuccessMacroFixture:
	
	def ExpectFailure(message as string, action as callable()):
	"""
	Expect that a test case will fail.
	Param message: The message to look for.
	Param action: The test case to invoke.
	"""
		try:
			action()
		except exception as NUnit.Framework.AssertionException:
			StringAssert.StartsWith(message, exception.Message)
		except exception:
			Assert.Fail("Unexpected exception: ${exception}")
	
	[Test]
	def SimpleTruth():
		expect true
	
	[Test]
	def FailSimpleTruth():
		ExpectFailure("test failed:\n4 == 2") do:
			expect 4 == 2
	
	[Test]
	def SimpleEquality():
		expect 5, _ == 5
	
	[Test]
	def FailSimpleEquality():
		ExpectFailure("test failed:\n2 == 17\nwith 2 == 2") do:
			expect 2, _ == 17
	
	[Test]
	def ComplexStatement():
		expect "hello", _[2] == (_ + _ + " ")[2 + 6]
	
	[Test]
	def FailComplexStatement():
		ExpectFailure(
			"test failed:\n" + \
			"'world'[2] == (('world' + 'world') + ' ')[(2 + 6)]\n" + \
			"with 'world' == world") do:
			expect "world", _[2] == (_ + _ + " ")[2 + 6]
	
	[Test]
	def MultiTest():
		expect "peaches", _ == "peach" + "es", _[4] == char('h')
	
	[Test]
	def FailMultiTest():
		ExpectFailure(
			"test failed:\n" + \
			"'carrots' == ('care' + 'rots')\n" + \
			"with 'carrots' == carrots") do:
			expect "carrots", _ == "care" + "rots", _[3] == char('r')
	
	[Test]
	def ComplexMulti():
		x = 4
		expect x, _ == _, 4 * _ == _ / _ * 16, -_ / 2 == (8 * -1) / _, true
	
	[Test]
	def FailComplexMulti():
		ExpectFailure(
			"test failed:\n" + \
			"(4 * x) == ((x / x) * 14)\n" + \
			"with x == 4") do:
			x = 4
			expect x, \
				_ == _, \
				4 * _ == _ / _ * 14, \
				-_ / 2 == (8 * -1) / _, \
				false
	
	[Test]
	def FailMissingException():
		ExpectFailure(
			"test failed:\n" + \
			"Expected exception of type InvalidOperationException, " + \
			"but no exception was raised.") do:
			expect InvalidOperationException:
				int.Parse("0")
	
	[Test]
	def SimpleException():
		expect InvalidOperationException:
			raise InvalidOperationException()
	
	[Test]
	def FailSimpleException():
		ExpectFailure(
			"test failed:\n" + \
			"Expected exception of type ArgumentException, " + \
			"but instead received " + \
			"System.InvalidOperationException: Invalid") do:
			expect ArgumentException:
				raise InvalidOperationException("Invalid")
	
	[Test]
	def MessageException():
		expect InvalidOperationException, "Something's\nwrong.":
			raise InvalidOperationException("Something's\nwrong.")
	
	[Test]
	def FailMessageException():
		ExpectFailure(
			"test failed:\n" + \
			"exception.Message == 'Somethings wrong.'\n" + \
			"with exception == " + \
			"System.InvalidOperationException: Something's wrong.") do:
			expect InvalidOperationException, "Somethings wrong.":
				raise InvalidOperationException("Something's wrong.")
	
	[Test]
	def InheritException():
		expect Exception:
			raise InvalidOperationException("Something's\nwrong.")
	
	[Test]
	def FailInheritException():
		ExpectFailure(
			"test failed:\n" + \
			"Expected exception of type ArgumentNullException, " + \
			"but instead received " + \
			"System.ArgumentException: Something's\nwrong.") do:
			expect ArgumentNullException:
				raise ArgumentException("Something's\nwrong.")
	
	[Test]
	def TestException():
		expect ArgumentNullException, _.ParamName == "x":
			raise ArgumentNullException("x")
	
	[Test]
	def FailTestException():
		ExpectFailure(
			"test failed:\n" + \
			"exception.InnerException is not null\n" + \
			"with exception == System.InvalidOperationException: Error") do:
			expect InvalidOperationException, _.InnerException is not null:
				raise InvalidOperationException("Error")
	
	[Test]
	def MultiException():
		expect InvalidOperationException, \
			_.Message == "Some message.", \
			"Some message.":
			raise InvalidOperationException("Some message.")
	
	[Test]
	def FailMultiException():
		ExpectFailure(
			"test failed:\n" + \
			"exception.Message == 'Some massage.'\n" + \
			"with exception == " + \
			"System.InvalidOperationException: Some message.") do:
			expect InvalidOperationException, \
				_.Message == "Some message.", \
				"Some massage.":
				raise InvalidOperationException("Some message.")
	
	[Test]
	def ComplexException():
		expect Exception, \
			"Error", \
			(_ as InvalidOperationException).InnerException == null, \
			" ${_.Message} ${_.Message} ".ToLowerInvariant().Trim() == \
				("error error"), \
			"Error":
			raise InvalidOperationException("Error")
	
	[Test]
	def FailComplexException():
		ExpectFailure(
			"test failed:\n" + \
			"\" \${exception.Message} \${exception.Message} \"" + \
			".ToUpperInvariant().Trim() == 'errata errata'\n" + \
			"with exception == " + \
			"System.InvalidOperationException: Errata") do:
			expect Exception, \
				"Errata", \
				(_ as InvalidOperationException).InnerException == null, \
				" ${_.Message} ${_.Message} ".ToUpperInvariant().Trim() == \
					("errata errata"), \
				"Error":
				raise InvalidOperationException("Errata")

	[Test]
	def NUnitException():
		# Should pass through
		ExpectFailure("NUnit exception\nuncaught. ") do:
			expect Exception:
				Assert.Fail("NUnit exception\nuncaught. ")

	[Test]
	def FailNUnitException():
		ExpectFailure("NUnit exception\nuncaught. ") do:
			expect ArgumentException:
				Assert.Fail("NUnit exception\nuncaught. ")

